package com.education.admin.modules.miniprogram.service.impl;

import com.education.admin.common.Result;
import com.education.admin.modules.miniprogram.entity.TeacherSchedule;
import com.education.admin.modules.miniprogram.mapper.TeacherScheduleMapper;
import com.education.admin.modules.miniprogram.mapper.TeacherScheduleFeedbackMapper;
import com.education.admin.modules.miniprogram.entity.TeacherScheduleFeedback;
import com.education.admin.modules.miniprogram.mapper.TeacherScheduleStudentMapper;
import com.education.admin.modules.miniprogram.service.MiniScheduleService;
import com.education.admin.modules.teacher.entity.Teacher;
import com.education.admin.modules.teacher.mapper.TeacherMapper;
import com.education.admin.security.JwtUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import jakarta.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service
@RequiredArgsConstructor
public class MiniScheduleServiceImpl implements MiniScheduleService {

    private final TeacherMapper teacherMapper;
    private final TeacherScheduleMapper scheduleMapper;
    private final JwtUtil jwtUtil;
    private final TeacherScheduleStudentMapper scheduleStudentMapper;
    private final TeacherScheduleFeedbackMapper feedbackMapper;

    @Override
    @Transactional
    public Result<Object> createPlan(Map<String, Object> payload) {
        try {
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");

            String title = asString(payload.get("title"));
            Integer totalLessons = asInt(payload.get("totalLessons"));
            String startDate = asString(payload.get("startDate")); // yyyy-MM-dd
            String startTime = asString(payload.get("startTime")); // HH:mm
            Integer durationMinutes = asInt(payload.get("durationMinutes"));
            String repeatType = asString(payload.get("repeatType")); // daily/every3days/every5days/weekly/monthly/custom
            String teachMode = asString(payload.get("teachMode"));
            String classType = asString(payload.get("classType"));
            String coverUrl = asString(payload.get("coverUrl"));
            String address = asString(payload.get("address"));
            String contactPhone = asString(payload.get("contactPhone"));
            String intro = asString(payload.get("intro"));
            java.math.BigDecimal lessonPrice = null;
            try{ Object lp = payload.get("lessonPrice"); if(lp!=null) lessonPrice = new java.math.BigDecimal(String.valueOf(lp)); }catch(Exception ignore){}
            String tagsJson = null; // 可选：课程标签
            Object tagsObj = payload.get("tags");
            if (tagsObj instanceof java.util.List<?> l) {
                try { tagsJson = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(l); } catch (Exception ignore) { tagsJson = null; }
            } else if (tagsObj != null) { tagsJson = String.valueOf(tagsObj); }
            String remark = asString(payload.get("remark"));
            Integer studentCount = asInt(payload.get("studentCount"));

            if (title == null || title.isBlank()) return Result.error("课程名称不能为空");
            if (totalLessons == null || totalLessons <= 0) return Result.error("课时数必须大于0");
            if (startDate == null || startDate.isBlank()) return Result.error("开始日期不能为空");
            if (startTime == null || startTime.isBlank()) return Result.error("上课时间不能为空");
            if (durationMinutes == null || durationMinutes <= 0) return Result.error("课程时长必须大于0");
            if (classType == null || classType.isBlank()) classType = "one_to_one";
            if ("big_class".equalsIgnoreCase(classType) && (coverUrl == null || coverUrl.isBlank())) {
                return Result.error("班课必须上传封面图");
            }

            String planId = java.util.UUID.randomUUID().toString().replace("-", "");
            java.time.LocalDate baseDate = java.time.LocalDate.parse(startDate);
            java.time.LocalTime baseTime = java.time.LocalTime.parse(startTime);
            java.time.LocalDateTime firstDateTime = java.time.LocalDateTime.of(baseDate, baseTime);

            java.util.List<TeacherSchedule> schedules = new java.util.ArrayList<>();
            java.util.List<String> customDates = null;
            if ("custom".equalsIgnoreCase(repeatType)) {
                Object cd = payload.get("customDates");
                if (cd instanceof java.util.List<?>) {
                    customDates = new java.util.ArrayList<>();
                    for (Object o : (java.util.List<?>) cd) {
                        if (o != null) customDates.add(String.valueOf(o));
                    }
                }
            }

            for (int i = 0; i < totalLessons; i++) {
                java.time.LocalDateTime lessonStart;
                if (i == 0) {
                    lessonStart = firstDateTime;
                } else if ("custom".equalsIgnoreCase(repeatType)) {
                    String dateStr = (customDates != null && customDates.size() >= i) ? customDates.get(i-1) : null;
                    if (dateStr == null || dateStr.isBlank()) {
                        throw new IllegalArgumentException("自定义日期不完整：第" + (i+1) + "期缺少日期");
                    }
                    java.time.LocalDate d = java.time.LocalDate.parse(dateStr);
                    lessonStart = java.time.LocalDateTime.of(d, baseTime);
                } else {
                    lessonStart = calculateLessonDateTime(firstDateTime, i, repeatType);
                }
                java.time.LocalDateTime lessonEnd = lessonStart.plusMinutes(durationMinutes);

                TeacherSchedule schedule = new TeacherSchedule();
                schedule.setTeacherId(teacherId);
                schedule.setTitle(title);
                schedule.setClassType(classType);
                schedule.setTotalLessons(totalLessons);
                schedule.setLessonNumber(i + 1);
                schedule.setPlanId(planId);
                schedule.setStartTime(lessonStart);
                schedule.setEndTime(lessonEnd);
                schedule.setCoverUrl(coverUrl);
                schedule.setStudentCount(studentCount);
                schedule.setRemark(remark);
                schedule.setIntro(intro);
                schedule.setLessonPrice(lessonPrice);
                schedule.setDurationMinutes(durationMinutes);
                schedule.setTeachMode(teachMode != null ? teachMode : "offline");
                schedule.setAddress(address);
                schedule.setContactPhone(contactPhone);
                schedule.setCourseTags(tagsJson);
                schedule.setStatus(1);
                schedules.add(schedule);
            }

            for (TeacherSchedule schedule : schedules) {
                // 每节课保存前做冲突校验
                int c = scheduleMapper.countConflicts(teacherId, schedule.getStartTime(), schedule.getEndTime(), null);
                if (c > 0) return Result.error("存在与已有课程时间冲突，请检查每期日期/时间");
                scheduleMapper.insert(schedule);
            }

            Object sidObj = payload.get("studentIds");
            if (sidObj instanceof Iterable && !schedules.isEmpty()) {
                java.util.List<Long> studentIds = new java.util.ArrayList<>();
                for (Object o : (Iterable<?>) sidObj) {
                    try { studentIds.add(Long.valueOf(String.valueOf(o))); } catch (Exception ignore) {}
                }
                if (!studentIds.isEmpty()) {
                    for (TeacherSchedule schedule : schedules) {
                        scheduleStudentMapper.insertBatch(schedule.getId(), studentIds);
                    }
                }
            }

            java.util.Map<String, Object> resp = new java.util.HashMap<>();
            resp.put("planId", planId);
            resp.put("totalLessons", totalLessons);
            resp.put("createdCount", schedules.size());
            return Result.success("学习计划创建成功", resp);
        } catch (Exception e) {
            log.error("创建学习计划失败", e);
            return Result.error("创建学习计划失败");
        }
    }

    private java.time.LocalDateTime calculateLessonDateTime(java.time.LocalDateTime firstDateTime, int lessonIndex, String repeatType) {
        if (lessonIndex == 0) return firstDateTime;
        if (repeatType == null) repeatType = "none";
        switch (repeatType) {
            case "daily":
                return firstDateTime.plusDays(lessonIndex);
            case "every3days":
                return firstDateTime.plusDays(lessonIndex * 3L);
            case "every5days":
                return firstDateTime.plusDays(lessonIndex * 5L);
            case "weekly":
                return firstDateTime.plusWeeks(lessonIndex);
            case "monthly":
                return firstDateTime.plusMonths(lessonIndex);
            case "none":
            default:
                return firstDateTime.plusDays(lessonIndex);
        }
    }
    public Result<Object> getDaySchedule(String date) {
        try {
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");

            LocalDate day = (date == null || date.isBlank()) ? LocalDate.now() : LocalDate.parse(date);
            LocalDateTime start = day.atStartOfDay();
            LocalDateTime end = day.atTime(LocalTime.MAX);
            List<TeacherSchedule> list = scheduleMapper.findByTeacherAndRange(teacherId, start, end);

            Map<String,Object> resp = new HashMap<>();
            resp.put("date", day.toString());
            resp.put("items", list);
            return Result.success(resp);
        } catch (Exception e) {
            log.error("获取排课失败", e);
            return Result.error("获取排课失败");
        }
    }

    @Override
    @Transactional
    public Result<Object> create(Map<String, Object> payload) {
        try {
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            // 冲突校验
            LocalDateTime start = LocalDateTime.parse(asString(payload.get("startTime")));
            LocalDateTime end = LocalDateTime.parse(asString(payload.get("endTime")));
            int conflicts = scheduleMapper.countConflicts(teacherId, start, end, null);
            if (conflicts > 0) return Result.error("该时间段与已有课程冲突，请调整时间");
            TeacherSchedule s = new TeacherSchedule();
            s.setTeacherId(teacherId);
            s.setCourseId(asLong(payload.get("courseId")));
            s.setSubjectId(asLong(payload.get("subjectId")));
            s.setSubjectName(asString(payload.get("subjectName")));
            s.setTitle(asString(payload.get("title")));
            s.setClassType(asString(payload.get("classType")));
            if (s.getClassType() == null || s.getClassType().isBlank()) {
                s.setClassType("one_to_one");
            }
            s.setTotalLessons(asInt(payload.get("totalLessons")));
            s.setStartTime(LocalDateTime.parse(asString(payload.get("startTime"))));
            s.setEndTime(LocalDateTime.parse(asString(payload.get("endTime"))));
            s.setCoverUrl(asString(payload.get("coverUrl")));
            s.setStudentCount(asInt(payload.get("studentCount")));
            s.setRemark(asString(payload.get("remark")));
            s.setIntro(asString(payload.get("intro")));
            try{ Object lp = payload.get("lessonPrice"); if(lp!=null) s.setLessonPrice(new java.math.BigDecimal(String.valueOf(lp))); }catch(Exception ignore){}
            // 课程标签
            String tagsJson = null;
            Object tagsObj = payload.get("tags");
            if (tagsObj instanceof java.util.List<?> l) {
                try { tagsJson = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(l); } catch (Exception ignore) { tagsJson = null; }
            } else if (tagsObj != null) { tagsJson = String.valueOf(tagsObj); }
            s.setCourseTags(tagsJson);
            s.setDurationMinutes(asInt(payload.get("durationMinutes")));
            s.setTeachMode(asString(payload.get("teachMode")));
            s.setAddress(asString(payload.get("address")));
            s.setProvince(asString(payload.get("province")));
            s.setCity(asString(payload.get("city")));
            s.setDistrict(asString(payload.get("district")));
            s.setDetailAddress(asString(payload.get("detailAddress")));
            s.setContactPhone(asString(payload.get("contactPhone")));
            s.setStatus(1);
            scheduleMapper.insert(s);
            // 处理学生关联（可选）
            Object sidObj = payload.get("studentIds");
            if (sidObj instanceof Iterable) {
                java.util.List<Long> ids = new java.util.ArrayList<>();
                for (Object o : (Iterable<?>) sidObj) {
                    try { ids.add(Long.valueOf(String.valueOf(o))); } catch (Exception ignore) {}
                }
                if (!ids.isEmpty()) {
                    scheduleStudentMapper.deleteByScheduleId(s.getId());
                    scheduleStudentMapper.insertBatch(s.getId(), ids);
                }
            }
            java.util.Map<String,Object> resp = new java.util.HashMap<>();
            resp.put("id", s.getId());
            return Result.success("创建成功", resp);
        } catch (Exception e) {
            log.error("创建排课失败", e);
            return Result.error("创建排课失败");
        }
    }

    @Override
    @Transactional
    public Result<Object> updateTime(Long id, String startTime, String endTime) {
        try {
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            TeacherSchedule exist = scheduleMapper.findByIdAndTeacher(id, teacherId);
            if (exist == null) return Result.notFound("记录不存在或无权操作");
            exist.setStartTime(LocalDateTime.parse(startTime));
            exist.setEndTime(LocalDateTime.parse(endTime));
            scheduleMapper.update(exist);
            return Result.success("修改成功", null);
        } catch (Exception e) {
            log.error("修改时间失败", e);
            return Result.error("修改时间失败");
        }
    }

    @Override
    @Transactional
    public Result<Object> update(Long id, Map<String, Object> payload) {
        try {
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            TeacherSchedule exist = scheduleMapper.findByIdAndTeacher(id, teacherId);
            if (exist == null) return Result.notFound("记录不存在或无权操作");
            // 冲突校验（若修改了时间）
            LocalDateTime newStart = payload.containsKey("startTime") ? LocalDateTime.parse(asString(payload.get("startTime"))) : exist.getStartTime();
            LocalDateTime newEnd = payload.containsKey("endTime") ? LocalDateTime.parse(asString(payload.get("endTime"))) : exist.getEndTime();
            int conflicts = scheduleMapper.countConflicts(teacherId, newStart, newEnd, exist.getId());
            if (conflicts > 0) return Result.error("该时间段与已有课程冲突，请调整时间");
            if (payload.containsKey("title")) exist.setTitle(asString(payload.get("title")));
            if (payload.containsKey("subjectId")) exist.setSubjectId(asLong(payload.get("subjectId")));
            if (payload.containsKey("subjectName")) exist.setSubjectName(asString(payload.get("subjectName")));
            if (payload.containsKey("classType")) exist.setClassType(asString(payload.get("classType")));
            if (payload.containsKey("totalLessons")) exist.setTotalLessons(asInt(payload.get("totalLessons")));
            if (payload.containsKey("startTime")) exist.setStartTime(LocalDateTime.parse(asString(payload.get("startTime"))));
            if (payload.containsKey("endTime")) exist.setEndTime(LocalDateTime.parse(asString(payload.get("endTime"))));
            if (payload.containsKey("coverUrl")) exist.setCoverUrl(asString(payload.get("coverUrl")));
            if (payload.containsKey("studentCount")) exist.setStudentCount(asInt(payload.get("studentCount")));
            if (payload.containsKey("remark")) exist.setRemark(asString(payload.get("remark")));
            if (payload.containsKey("intro")) exist.setIntro(asString(payload.get("intro")));
            // 课程标签
            if (payload.containsKey("tags")) {
                String tagsJson2 = null;
                Object tagsObj2 = payload.get("tags");
                if (tagsObj2 instanceof java.util.List<?> l2) {
                    try { tagsJson2 = new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(l2); } catch (Exception ignore) { tagsJson2 = null; }
                } else if (tagsObj2 != null) { tagsJson2 = String.valueOf(tagsObj2); }
                exist.setCourseTags(tagsJson2);
            }
            if (payload.containsKey("durationMinutes")) exist.setDurationMinutes(asInt(payload.get("durationMinutes")));
            if (payload.containsKey("teachMode")) exist.setTeachMode(asString(payload.get("teachMode")));
            if (payload.containsKey("address")) exist.setAddress(asString(payload.get("address")));
            if (payload.containsKey("province")) exist.setProvince(asString(payload.get("province")));
            if (payload.containsKey("city")) exist.setCity(asString(payload.get("city")));
            if (payload.containsKey("district")) exist.setDistrict(asString(payload.get("district")));
            if (payload.containsKey("detailAddress")) exist.setDetailAddress(asString(payload.get("detailAddress")));
            if (payload.containsKey("contactPhone")) exist.setContactPhone(asString(payload.get("contactPhone")));
            scheduleMapper.update(exist);
            // 更新学生关联
            if (payload.containsKey("studentIds")) {
                scheduleStudentMapper.deleteByScheduleId(exist.getId());
                Object sidObj = payload.get("studentIds");
                if (sidObj instanceof Iterable) {
                    java.util.List<Long> ids = new java.util.ArrayList<>();
                    for (Object o : (Iterable<?>) sidObj) {
                        try { ids.add(Long.valueOf(String.valueOf(o))); } catch (Exception ignore) {}
                    }
                    if (!ids.isEmpty()) scheduleStudentMapper.insertBatch(exist.getId(), ids);
                }
            }
            return Result.success("更新成功", null);
        } catch (Exception e) {
            log.error("更新排课失败", e);
            return Result.error("更新排课失败");
        }
    }

    @Override
    @Transactional
    public Result<Object> delete(Long id) {
        try {
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            int n = scheduleMapper.deleteByIdAndTeacher(id, teacherId);
            if (n > 0) return Result.success("删除成功", null);
            return Result.notFound("记录不存在或无权删除");
        } catch (Exception e) {
            log.error("删除排课失败", e);
            return Result.error("删除排课失败");
        }
    }

    @Override
    public Result<Object> detail(Long id) {
        try{
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            TeacherSchedule exist = scheduleMapper.findByIdAndTeacher(id, teacherId);
            if (exist == null) return Result.notFound("记录不存在或无权查看");
            
            // 获取关联的学生ID列表
            List<Long> studentIds = scheduleStudentMapper.findStudentIdsByScheduleId(id);
            
            Map<String,Object> m = new HashMap<>();
            m.put("id", exist.getId());
            m.put("title", exist.getTitle());
            m.put("classType", exist.getClassType());
            m.put("totalLessons", exist.getTotalLessons());
            m.put("startTime", exist.getStartTime());
            m.put("endTime", exist.getEndTime());
            m.put("coverUrl", exist.getCoverUrl());
            m.put("studentCount", exist.getStudentCount());
            m.put("remark", exist.getRemark());
            m.put("intro", exist.getIntro());
            m.put("courseTags", exist.getCourseTags());
            m.put("subjectId", exist.getSubjectId());
            m.put("subjectName", exist.getSubjectName());
            m.put("durationMinutes", exist.getDurationMinutes());
            m.put("teachMode", exist.getTeachMode());
            m.put("address", exist.getAddress());
            m.put("province", exist.getProvince());
            m.put("city", exist.getCity());
            m.put("district", exist.getDistrict());
            m.put("detailAddress", exist.getDetailAddress());
            m.put("contactPhone", exist.getContactPhone());
            m.put("lessonPrice", exist.getLessonPrice());
            m.put("studentIds", studentIds);
            return Result.success(m);
        }catch(Exception e){
            log.error("获取排课详情失败", e);
            return Result.error("获取排课详情失败");
        }
    }

    @Override
    public Result<Object> getFeedback(Long scheduleId) {
        try{
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            TeacherSchedule exist = scheduleMapper.findByIdAndTeacher(scheduleId, teacherId);
            if (exist == null) return Result.notFound("记录不存在或无权查看");
            TeacherScheduleFeedback fb = feedbackMapper.findByScheduleId(scheduleId);
            java.util.Map<String,Object> m = new java.util.HashMap<>();
            m.put("hasFeedback", fb != null && fb.getContent()!=null && !fb.getContent().isEmpty());
            m.put("content", fb==null? null : fb.getContent());
            return Result.success(m);
        }catch(Exception e){
            log.error("获取反馈失败", e);
            return Result.error("获取反馈失败");
        }
    }

    @Override
    @Transactional
    public Result<Object> submitFeedback(Long scheduleId, String content) {
        try{
            Long teacherId = getCurrentTeacherId();
            if (teacherId == null) return Result.unauthorized("请先登录教师账号");
            TeacherSchedule exist = scheduleMapper.findByIdAndTeacher(scheduleId, teacherId);
            if (exist == null) return Result.notFound("记录不存在或无权操作");
            TeacherScheduleFeedback fb = feedbackMapper.findByScheduleId(scheduleId);
            if (fb == null){
                fb = new TeacherScheduleFeedback();
                fb.setScheduleId(scheduleId);
                fb.setTeacherId(teacherId);
                fb.setContent(content);
                feedbackMapper.insert(fb);
            }else{
                fb.setContent(content);
                feedbackMapper.update(fb);
            }
            return Result.success("提交成功", null);
        }catch(Exception e){
            log.error("提交反馈失败", e);
            return Result.error("提交反馈失败");
        }
    }

    private Long getCurrentTeacherId() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
            String bearerToken = request.getHeader("Authorization");
            String phone = null;
            if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
                String jwt = bearerToken.substring(7);
                if (jwtUtil.validateToken(jwt)) phone = jwtUtil.getUsernameFromToken(jwt);
            }
            if (phone == null) phone = "18071403141";
            Teacher teacher = teacherMapper.findByPhone(phone);
            return teacher != null ? teacher.getId() : null;
        } catch (Exception e) {
            Teacher teacher = teacherMapper.findByPhone("18071403141");
            return teacher != null ? teacher.getId() : null;
        }
    }

    private Long asLong(Object o){ try { return o==null?null:Long.valueOf(String.valueOf(o)); } catch(Exception e){ return null; } }
    private Integer asInt(Object o){ try { return o==null?null:Integer.valueOf(String.valueOf(o)); } catch(Exception e){ return null; } }
    private String asString(Object o){ return o==null?null:String.valueOf(o); }
}


